import requests,json,time,os,urllib     #载入json模块

bianma = 'utf-8'
qingqiutou = {
    "Host": 'api.bilibili.com',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0',
    'Accept': '*/*',
    'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
    'Accept-Encoding': 'gzip, deflate, br',
    'Connection': 'keep-alive',
    }

def duoge(av):            #输入AV号执行下载任务
    pcidj = pn(av)      #获取视频目录json
    p = len(pcidj)             #查询视频P数，并存入变量p
    i = 0                      #计数器
    while i<p:                 #循环多P视频
        cid = pcidj[i]['cid']              #获取该P视频的cid
        i += 1                             #计数器+1
        xiaZaiDanPZiMu(av,cid,i)           #下载该P视频的字幕
        print ('【任务总进度：%s/%sP】\n'%(i,p))   #汇报任务进度（以P算）
    print ('\n\n*** 任务完成 ***\n')    #最终完成报告

def xiaZaiDanPZiMu(aid,cid,p):  #根据cid下载该P视频内的全部字幕（全部语言）
    url = 'https://api.bilibili.com/x/player/v2?bvid=%s&cid=%s'%(aid,cid)
    jieshou = requests.get(url,headers=qingqiutou)
    zidian = json.loads(jieshou.text)
    yz = zidian['data']['subtitle']['subtitles']      #字幕信息列表
    ming = aid
    i = 0               #计数器
    ii = len(yz)        #字幕语言数量
    if ii == 0:print('【警告】P%s无字幕！'%p)
    while i<ii:                        #循环下载、处理多个语言
        lan = yz[i]['lan']                              #获取字幕的语言编号（ZH JP EN之类）
        suburl = 'http:'+yz[i]['subtitle_url']                  #获取字幕的URL
        mingl = ming + '_P' + str(p) +'_' + lan         #根据视频名、P数和语言生成字幕文件名
        urllib.request.urlretrieve(suburl,'%s.json'%mingl)  #下载json
        jsonZhuanSrt(mingl)                                 #处理json输出srt
        i += 1
        print ('P%s 第%s种语言下载完成，进度：%s/%s'%(p,i,i,ii))    #报告任务进度（以该P视频的字幕语言数算）
        time.sleep(0.2)

def qv(zifu):           #去除特殊符号
    zifu = zifu.replace('/','、')
    zifu = zifu.replace('\\','、')
    zifu = zifu.replace('|','、')
    zifu = zifu.replace('*','X')
    zifu = zifu.replace(':','：')
    zifu = zifu.replace('?','？')
    zifu = zifu.replace('<','《')
    zifu = zifu.replace('>','》')
    zifu = zifu.replace('\"','“')
    zifu = zifu.replace('\"','”')
    return zifu    

def pn(av):                   #获取视频列表json
    url = 'https://api.bilibili.com/x/player/pagelist?bvid=%s'%av #创建URL
    jieshou = requests.get(url,headers=qingqiutou)              #获取Json
    zidian = json.loads(jieshou.text)['data']                   #载入字典
    print ('视频目录获取成功！共%sP。\n'%len(zidian))             #汇报
    return zidian             #返回列表

def jsonZhuanSrt(ming):                       #传入Json字幕文件名，输出Srt字幕（下载Json字幕后）
        wenjian = open('%s.json'%ming,encoding='utf-8')        #载入Json文件
        zidian = json.loads(wenjian.read())['body']            #Json传入字典
        wenjian.close()                                        #关闭文件
        os.remove('%s.json'%ming)                              #删除无用Json文件
        wenjian = open('%s.srt'%ming,'w',encoding=bianma) #创建srt字幕文件
        i = 0                                   #计数变量
        while i<len(zidian):                    #循环处理每一条字幕
                f = round(zidian[i]['from'],3)      #开始时间 （round(n，3)四舍五入为三位小数）
                t = round(zidian[i]['to'],3)        #结束时间
                c = zidian[i]['content']            #字幕
                ff = time.strftime("%H:%M:%S",time.gmtime(f)) + ',' + miao(f)   #秒数转 时:分:秒 格式，加逗号和毫秒
                tt = time.strftime("%H:%M:%S",time.gmtime(t)) + ',' + miao(t)   #结束时间，处理方式同上
                shujv = str(i+1)+'\n' + ff+' '+'-->'+' '+tt+'\n' + c+'\n\n'     #格式化为Srt字幕
                wenjian.write(shujv)                                            #写入
                i += 1                                                          #计数器+1
        print ('%s OK.'%ming)

def miao(miao):                       #修正毫秒为三位
    miao = str(miao).partition('.')[2]    #取小数部分
    if len(miao)==0:miao = '000'          #补齐三位小数
    if len(miao)==1:miao = miao + '00'
    if len(miao)==2:miao = miao + '0'
    return miao                           #返回标准三位的毫秒数